/**
 * 
 */
package com.usc.nearbyus;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.Preference;
import android.util.Log;

/**
 * @author pranav
 *
 */
public class GPSLoggerService extends Service implements LocationListener {


	private String TAG = "GPSLoggerService";
	private LocationManager manager;
	private static final int gpsMinTime = 250;
	private static final int gpsMinDistance = 0;
	private static final int TIMER_DELAY = 500;
	private static final int INITIAL_TIMER_DELAY = 1500;
	private double latitude;
	private double longitude;
	private Timer monitoringTimer;
	WifiManager wifi;
	private WiFiScanReceiver receiver;
	private ReadingsDbAdapter mDbAdapter;
	//private boolean desiredWifiNetworkFound = false;
	private Timer wifiMonitoringTimer;

	public GPSLoggerService(){
		Log.d(TAG, "GPSLoggerService Constructor");				
	}

	/* (non-Javadoc)
	 * @see android.location.LocationListener#onLocationChanged(android.location.Location)
	 */
	@Override
	public void onLocationChanged(Location location) {

		Log.d(TAG, "onLocationChanged()");		
		latitude = location.getLatitude();
		longitude = location.getLongitude();
		
		
		//saveReadings(latitude, longitude,receiver.getResults());
		
		float[] results = new float[3];  		
		Location.distanceBetween(latitude, longitude, (int)(34.022571*1E6), (int)(-118.283175*1E6), results);
		float distance = results[0];
		
		Log.d(TAG, "User distance from the center of USC : " + distance);
		
		if(distance < 2500000){			
			Log.d(TAG, "We are inside geofence range so saving the reading");
			saveReadings(latitude, longitude,receiver.getResults());
		}
		
				
		/*if(findIfInsideAreaOfInterest()){
			startGPSMonitoringTimer();
			startGPSLoggingService();
			
		}else{
			stopWifiService();
			stopGPSLoggingService();
		}*/

	}

	/* (non-Javadoc)
	 * @see android.location.LocationListener#onProviderDisabled(java.lang.String)
	 */
	@Override
	public void onProviderDisabled(String provider) {
		Log.d(TAG,"Provider is disabled : " + provider);
	}

	/* (non-Javadoc)
	 * @see android.location.LocationListener#onProviderEnabled(java.lang.String)
	 */
	@Override
	public void onProviderEnabled(String provider) {
		Log.d(TAG,"Provider is enabled : " + provider);
	}

	/* (non-Javadoc)
	 * @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle)
	 */
	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		Log.d(TAG, "onStatusChanged()");
	}

	/* (non-Javadoc)
	 * @see android.app.Service#onBind(android.content.Intent)
	 */
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind() called - Returns null");
		return null;
	}

	/* (non-Javadoc)
	 * @see android.app.Service#onCreate()
	 */
	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG, "onCreate() called");
	}
	
	

	/* (non-Javadoc)
	 * @see android.app.Service#onDestroy()
	 */
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		monitoringTimer.cancel();
		monitoringTimer = null;
		manager.removeUpdates(GPSLoggerService.this);
		stopSelf();	
	}

	/* (non-Javadoc)
	 * @see android.app.Service#onStart(android.content.Intent, int)
	 */
	@Override
	public void onStart(Intent intent, int startId) {		

		super.onStart(intent, startId);
		Log.d(TAG,"onStart() called");
		startWifiService();
		startGPSLoggingService();
		startGPSMonitoringTimer();
	//	startWifiTimer();
	//	startGPSMonitoringTimer();	

	}	
	
	
	private void startWifiTimer() {
		Log.d(TAG,"Wifi Timer Started");		
		wifiMonitoringTimer = new Timer();

		wifiMonitoringTimer.scheduleAtFixedRate(
				new TimerTask() {

					@Override
					public void run() {
						Log.d(TAG, "Inside WifiTimer run");
						if(receiver.getResults() != null){
							Log.d(TAG, "WifiTimer Stopped");
							wifiMonitoringTimer.cancel();
							wifiMonitoringTimer = null;
							
							
						/*	if(findIfInsideAreaOfInterest()){
								Log.d(TAG, "Network detected");
								startGPSLoggingService();
								startGPSMonitoringTimer();
								
							}else{
								Log.d(TAG, "Network not detected");
								stopWifiService();
							}			*/			
							
						}

					}
				},GPSLoggerService.INITIAL_TIMER_DELAY,
				  GPSLoggerService.TIMER_DELAY);		
	}

	/**
	 * This method finds out whether we are inside the desired geo-fence region or not
	 */
	private boolean findIfInsideAreaOfInterest() {

		for(ScanResult result : receiver.getResults()){
			if(result.SSID.contains("USC Wireless") || result.SSID.contains("OhM")){
				Log.d(TAG, "Desired wi-fi network is available : " + result.SSID);
				return true;			
			}
		}	
		
		return false;		

	}

	private void startWifiService() {

		Log.d(TAG,"Start WifiService");		
		wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);	

		// Register Broadcast Receiver
		if (receiver == null){
			receiver = new WiFiScanReceiver(this);
		}

		registerReceiver(receiver, new IntentFilter(
				WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

	}	


	private void startGPSMonitoringTimer() {

		Log.d(TAG,"Start GPS Monitoring Timer");
		monitoringTimer = new Timer();		

		monitoringTimer.scheduleAtFixedRate(
				new TimerTask()
				{
					@Override
					public void run()
					{
						Log.d(TAG, "GPSTimer : inside Run");
						Log.d(TAG, "Latitude and longitude in GPS Timer : " + latitude +" "+ longitude);
						if (longitude != 0.0 && latitude != 0.0)
						{
							
							/*Intent intent = new Intent();
							intent.putExtra("latitude", latitude);
							intent.putExtra("longitude", longitude);							
							*/
							
							
							// saveReadings(latitude, longitude,receiver.getResults());

						}
					}
				}, 
				GPSLoggerService.INITIAL_TIMER_DELAY,
				GPSLoggerService.TIMER_DELAY);

	}

	protected void stopWifiService() {
		Log.d(TAG,"Stop WIFI Service");
		unregisterReceiver(receiver);
	}

	protected void saveReadings(double latitude, double longitude, List<ScanResult> results) {

		mDbAdapter = new ReadingsDbAdapter(getApplicationContext());
		mDbAdapter.open();

		Log.d(TAG, results.size() + " readings stored for latitude : " + latitude + " longitude : " + longitude);
		Calendar calendar = Calendar.getInstance();

		SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String timestamp = dateFormatter.format(calendar.getTime());	
				
		String userid = UserSettings.getUserID(this);
		Log.d(TAG, "userid before the change : " + userid);
		if(userid.equalsIgnoreCase("notset")){
			UserSettings.setUserID(this,String.valueOf(Math.random()));
		}
		boolean isflagged = false;

		Log.d(TAG, "userid after the change : " + userid);
		for (ScanResult result : results) {				
			mDbAdapter.createReading(longitude, latitude, timestamp, userid, isflagged, result);		
		}
		
		mDbAdapter.close();

	}

	protected void stopGPSLoggingService() {
		Log.d(TAG,"Stop GPS Service");
		monitoringTimer.cancel();
		monitoringTimer = null;
		manager.removeUpdates(GPSLoggerService.this);
		stopSelf();		
	}

	
	private void startGPSLoggingService() {

		Log.d(TAG,"Start GPS Logging Service");

		if (manager == null)
		{
			manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		}

		final Criteria criteria = new Criteria();		
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		criteria.setAltitudeRequired(true);
		criteria.setBearingRequired(false);
		criteria.setCostAllowed(true);
		criteria.setPowerRequirement(Criteria.POWER_LOW);

		final String bestProvider = manager.getBestProvider(criteria, true);

		if (bestProvider != null && bestProvider.length() > 0)
		{
			Log.d(TAG,"Best Provider : " + bestProvider);
			manager.requestLocationUpdates(bestProvider, gpsMinTime,gpsMinDistance, this);
		}
		else
		{
			final List<String> providers = manager.getProviders(true);

			for (final String provider : providers)
			{
				Log.d(TAG,"Best Provider not available");
				manager.requestLocationUpdates(provider, gpsMinTime, gpsMinDistance, this);
			}
		}

	}	


}
